#include <unistd.h>
#include <cstring>
#include <ctime>
#include <dirent.h>
#include <signal.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <execinfo.h> // for backtrace()
#include <cxxabi.h>   // for abi::__cxa_demangle()
#include <algorithm>  // for std::transfrom()
#include <stdarg.h>
#include <sstream>
#include <fstream>
#include "util.h"
#include "fiber.h"
#include "log.h"

// Done

// long syscall(long number, unsigned long arg0, unsigned long arg1, unsigned long arg2,
//             unsigned long arg3, unsigned long arg4, unsigned long arg5);
// number：系统调用号，用于标识要执行的系统调用。
// arg0 至 arg5：传递给系统调用的参数。通常，这些参数代表输入数据或控制选项。
pid_t GetThreadId()
{
    return syscall(SYS_gettid);
}

uint64_t GetFiberId()
{
    return Fiber::GetFiberId();
}

// struct timespec
// {
//     time_t tv_sec; // 秒（整数，从纪元开始）
//     long tv_nsec;  // 纳秒（整数，范围从 0 到 999999999）
// };
uint64_t GetElapsedMS()
{
    struct timespec ts = {0};
    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
    return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}

std::string GetThreadName()
{
    char thread_name[16] = {0};
    pthread_getname_np(pthread_self(), thread_name, 16);
    return std::string(thread_name);
}

void SetThreadName(const std::string &name)
{
    pthread_setname_np(pthread_self(), name.substr(0, 15).c_str());
}

// 解析 C++ 类型名称
static std::string demangle(const char *str)
{
    size_t size = 0;
    int status = 0;
    std::string ans;
    ans.resize(256);
    if (1 == sscanf(str, "%*[^(]%255[^)+]", &ans[0]))
    {
        char *v = abi::__cxa_demangle(&ans[0], nullptr, &size, &status);
        if (v)
        {
            std::string result(v);
            free(v);
            return result;
        }
    }

    if (1 == sscanf(str, "%255s", &ans[0]))
    {
        return ans;
    }
    return str;
}

// 获取当前的调用栈
// bt 保存调用栈
// size 最多返回次数
// skip 跳过栈顶顶层数
// 调用 backtrace 函数获取当前线程的调用堆栈。
// 调用 backtrace_symbols 函数将堆栈跟踪中的每个地址转换为可读的字符串。
// 从跳过的帧数（skip）开始，将堆栈跟踪中的每个字符串添加到 bt 向量中。
void Backtrace(std::vector<std::string> &bt, int size, int skip)
{
    void **array = (void **)malloc(sizeof(void *) * size);
    size_t s = ::backtrace(array, size);

    char **strings = backtrace_symbols(array, s);
    if (strings == nullptr)
    {
        LOG(ERROR,"backtrace_symbols error");
        return;
    }

    for (size_t i = skip; i < s; ++i)
    {
        bt.push_back(strings[i]);
    }
}

std::string BacktraceToString(int size, int skip, const std::string &prefix)
{
    std::vector<std::string> bt;
    Backtrace(bt, size, skip);
    std::stringstream ss;
    for (size_t i = 0; i < bt.size(); ++i)
    {
        ss << prefix << bt[i] << std::endl;
    }
    return ss.str();
}

// 获取当前时间的毫秒
uint64_t GetCurrentMS()
{
    struct timeval tv;
    gettimeofday(&tv, nullptr);
    return tv.tv_sec * 1000ul + tv.tv_usec / 1000;
}

// 获取当前时间的微妙
uint64_t GetCurrentNS()
{
    struct timeval tv;
    gettimeofday(&tv, nullptr);
    return tv.tv_sec * 1000 * 1000ul + tv.tv_usec;
}

// 字符串转大写
std::string ToUpper(const std::string &name)
{
    std::string ret = name;
    std::transform(ret.begin(), ret.end(), ret.begin(), ::toupper);
    return ret;
}

// 字符串转小写
std::string ToLower(const std::string &name)
{
    std::string ret = name;
    std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
    return ret;
}

// 日期时间转字符串
// struct tm *localtime_r(const time_t *timep, struct tm *result);将Unix时间戳（自1970年1月1日以来的秒数）转换为本地时间结构（tm结构）
// size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);将tm结构表示的时间格式化为指定格式的字符串
std::string Time2Str(time_t ts, const std::string &format)
{
    struct tm tm;
    if (localtime_r(&ts, &tm) != nullptr)
    {
        LOG(ERROR,"Failed to convert timestamp to local time");
        return "";
    }
    char buffer[64];
    strftime(buffer, sizeof(buffer), format.c_str(), &tm);
    return buffer;
}

// 字符串转日期
// char *strptime(const char *s, const char *format, struct tm *tm);
time_t Str2Time(const char *str, const char *format)
{
    struct tm tm;
    memset(&tm, 0, sizeof(tm));
    if (!strptime(str, format, &tm))
    {
        return 0;
    }
    return mktime(&tm);
}

// 文件系统操作类
// class FSUtil

// 递归列举指定目录下所有指定后缀的常规文件,如果不指定,则遍历所有文件,返回文件名带路径
// struct dirent {
//     ino_t          d_ino;       // 文件的inode号
//     off_t          d_off;       // 文件在目录中的偏移量
//     unsigned short d_reclen;    // 记录的长度
//     unsigned char  d_type;      // 文件类型（DT_DIR, DT_REG等）
//     char           d_name[256]; // 文件名
// };
void FSUtil::ListAllFile(std::vector<std::string> &files, const std::string &path, const std::string &subfix)
{
    // 判断是否课进入
    if (access(path.c_str(), 0) != 0)
        return;

    DIR *dir = opendir(path.c_str());
    if (dir == nullptr)
        return;

    struct dirent *dp = nullptr;
    // readdir 子目录或普通文件
    while ((dp = readdir(dir)) != nullptr)
    {
        if (dp->d_type == DT_DIR)
        {
            if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
            {
                continue;
            }
            ListAllFile(files, path + "/" + dp->d_name, subfix);
        }
        else if (dp->d_type == DT_REG)
        {
            std::string filename(dp->d_name);
            if (subfix.empty())
            {
                files.push_back(path + "/" + filename);
            }
            else
            {
                if (filename.size() < subfix.size())
                {
                    continue;
                }
                if (filename.substr(filename.size() - subfix.size()) == subfix)
                {
                    files.push_back(path + "/" + filename);
                }
            }
        }
    }
    closedir(dir);
}

static int __lstat(const char *file, struct stat *st = nullptr)
{
    struct stat lst;
    // lstat函数用于获取文件或目录的状态信息。
    int ret = lstat(file, &lst);
    if (st)
    {
        *st = lst;
    }
    return ret;
}

static int __mkdir(const char *dirname)
{
    if (access(dirname, F_OK) == 0)
        return 0;
    // S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH来设置读、写和执行权限
    return mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
}

// 创建路径,相当于mkdir -p
bool FSUtil::Mkdir(const std::string &dirname)
{
    if (__lstat(dirname.c_str()) == 0)
        return true;

    // 函数创建一个指向目录路径的副本
    char *path = strdup(dirname.c_str());
    // 使用strchr查找路径中的第一个/字符（从第二个字符开始，因为第一个字符总是/）。这将用于遍历路径中的每个目录级别
    char *ptr = strchr(path + 1, '/');

    do
    {
        for (; ptr; *ptr = '/', ptr = strchr(ptr + 1, '/'))
        {
            // 将当前找到的/字符替换为\0，从而截断路径以仅包含当前目录级别
            *ptr = '\0';
            if (__mkdir(path) != 0)
                break;
        }
        if (ptr != nullptr)
            break;
        else if (__mkdir(path) != 0)
            break;
        free(path);
        return true;
    } while (0);

    free(path);
    return false;
}

// 判断指定pid文件指定的pid是否正在运行,使用kill(pid,0)的方式判断
// pidfile 保存进程号的文件
bool FSUtil::isRunningPidfile(const std::string &pidfile)
{
    if (__lstat(pidfile.c_str()) != 0)
        return false;

    std::ifstream ifs(pidfile);
    std::string line;
    if (!ifs || !std::getline(ifs, line))
        return false;

    if (line.empty())
        return false;
    pid_t pid = atoi(line.c_str());
    if (pid <= 1)
        return false;
    // 它仅用于检查进程是否存在。如果进程存在且仍在运行，kill(pid, 0)将成功执行并返回0。
    // 如果进程不存在或已终止，kill(pid, 0)将失败并设置errno以指示错误。
    if (kill(pid, 0) != 0)
        return false;
    return true;
}

// 删除文件,参考unlink
bool FSUtil::Unlink(const std::string &filename, bool exist)
{
    if (!exist && __lstat(filename.c_str()))
        return true;

    // int unlink(const char *pathname);用于删除指定的文件
    return ::unlink(filename.c_str()) == 0;
}

// 删除文件或路径
bool FSUtil::Rm(const std::string &path)
{
    struct stat st;
    if (lstat(path.c_str(), &st))
        return true;

    if (!(st.st_mode & S_IFDIR))
    {
        return Unlink(path);
    }

    DIR *dir = opendir(path.c_str());
    if (!dir)
        return false;

    bool ret = true;
    struct dirent *dp = nullptr;
    while ((dp = readdir(dir)))
    {
        if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
        {
            continue;
        }
        std::string dirname = path + "/" + dp->d_name;
        return Rm(dirname);
    }
    closedir(dir);
    if (::rmdir(path.c_str()))
        ret = false;

    return ret;
}

// 移动文件或路径,内部实现是先Rm(to),再rename(from,to),参考rename
bool FSUtil::Mv(const std::string &from, const std::string &to)
{
    if (Rm(to) == false)
        return false;
    return rename(from.c_str(), to.c_str()) == 0;
}

// 返回绝对路径,参考realpath(3)
// 路径这个的符号链接会被解析成实际的路径,删除多余的'.' '..'和'/'
bool FSUtil::RealPath(const std::string &path, std::string &rpath)
{
    if (__lstat(path.c_str()))
        return false;

    char *ptr = ::realpath(path.c_str(), nullptr);
    if (nullptr == ptr)
        return false;

    std::string(ptr).swap(rpath);
    free(ptr);
    return true;
}

// 创建符号链接，参考
// int symlink(const char *target, const char *source);
// target：一个指向目标文件或目录路径的C风格字符串。
// source：一个指向新创建的符号链接路径的C风格字符串。
bool FSUtil::Symlink(const std::string &from, const std::string &to)
{
    if (Rm(to) == false)
        return false;
    return ::symlink(from.c_str(), to.c_str());
}

// 返回文件,即路径中最后一个/前面部分,不包括/本身,如果未找到,则返回filename
std::string FSUtil::Dirname(const std::string &filename)
{
    if (filename.empty())
        return ".";
    auto pos = filename.rfind("/");
    if (pos == 0)
        return "/";
    else if (pos == std::string::npos)
        return ".";
    else
        return filename.substr(0, pos);
}

// 返回文件名,即路径中最后一个/后面部分
std::string FSUtil::Basename(const std::string &filename)
{
    if (filename.empty())
        return filename;
    auto pos = filename.rfind("/");
    if (pos == std::string::npos)
        return filename;
    else
        return filename.substr(pos + 1);
}

// 以只读方式打开文件
bool FSUtil::OpenForRead(std::ifstream &ifs, const std::string &filename, std::ios_base::openmode mode)
{
    ifs.open(filename.c_str(), mode);
    return ifs.is_open();
}

// 以只写方式打卡文件
bool FSUtil::OpenForWrite(std::ofstream &ofs, const std::string &filename, std::ios_base::openmode mode)
{
    ofs.open(filename.c_str(), mode);
    if (!ofs.is_open())
    {
        std::string dir = Dirname(filename);
        Mkdir(dir);
        ofs.open(filename.c_str(), mode);
    }

    return ofs.is_open();
}

// 转字符,返回*str.begin()
int8_t TypeUtil::Tochar(const std::string &str)
{
    if (str.empty())
        return 0;
    return *str.begin();
}
// atoi
uint64_t TypeUtil::Atoi(const std::string &str)
{
    if (str.empty())
        return 0;
    // strtoull 函数的第一个参数是要转换的字符串
    // 第二个参数是一个指向字符指针的指针，用于存储转换后剩余字符串的位置，
    // 第三个参数是转换的基数（例如，10 表示十进制）。
    return strtoull(str.c_str(), nullptr, 10);
}

// atof
double TypeUtil::Atof(const std::string &str)
{
    if (str.empty())
        return 0;
    return atof(str.c_str());
}
// 返回str[0]
uint8_t TypeUtil::Tochar(const char *str)
{
    if (str == nullptr)
        return 0;
    return str[0];
}
// atoi
uint64_t TypeUtil::Atoi(const char *str)
{
    if (str == nullptr)
        return 0;
    return strtoull(str, nullptr, 10);
}
// atof
double TypeUtil::Atof(const char *str)
{
    if (str == nullptr)
        return 0;
    return atof(str);
}

// printf 风格的字符串转化,返回格式化后的string
std::string StringUtil::Format(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    auto v = Formatv(fmt, ap);
    va_end(ap);
    return v;
}
// vprintf 风格的字符串转化,返回格式化后的string
std::string StringUtil::Formatv(const char *fmt, va_list ap)
{
    char *buffer = nullptr;
    auto len = vasprintf(&buffer, fmt, ap);
    if (len == -1)
        return "";

    std::string ret(buffer, len);
    free(buffer);
    return ret;
}

// 数组用于标识 URI 中允许的字符，数组的索引表示字符的 ASCII 码，数组的值表示该字符是否允许出现在 URI 中（1 表示允许，0 表示不允许）。
static const char uri_chars[256] = {
    /* 0 */
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    1,
    1,
    0,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    0,
    0,
    0,
    1,
    0,
    0,
    /* 64 */
    0,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    0,
    0,
    0,
    0,
    1,
    0,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    0,
    0,
    0,
    1,
    0,
    /* 128 */
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    /* 192 */
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
};

// xdigit_chars 数组表示十六进制数字字符的映射，用于 URL 解码过程中将 % 符号后的两个字符转换为对应的字节。
static const char xdigit_chars[256] = {
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    1,
    2,
    3,
    4,
    5,
    6,
    7,
    8,
    9,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    10,
    11,
    12,
    13,
    14,
    15,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    10,
    11,
    12,
    13,
    14,
    15,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
};

// 宏用于检查给定字符是否在 URI 中允许出现。它将输入字符转换为无符号字符，然后使用 uri_chars 数组检查该字符是否允许。
#define CHAR_IS_UNRESERVED(c) (uri_chars[(unsigned char)(c)])

// url解码
std::string StringUtil::UrlEncode(const std::string &str, bool convert_plus_to_space)
{
    static const char *hexdigits = "0123456789ABCDEF";
    std::string *ss = nullptr;
    const char *end = str.c_str() + str.size();
    for (const char *c = str.c_str(); c < end; ++c)
    {
        if (CHAR_IS_UNRESERVED(*c))
        {
            if (!ss)
            {
                ss = new std::string;
                ss->reserve(str.size() * 1.2);
                ss->append(str.c_str(), c - str.c_str());
            }
            if (*c == ' ' && convert_plus_to_space)
            {
                ss->append(1, '+');
            }
            else
            {
                ss->append(1, '%');
                // 提取出高 4 位
                ss->append(1, hexdigits[(uint8_t)*c >> 4]);
                // 提取出低 4 位
                ss->append(1, hexdigits[*c & 0xf]);
            }
        }
        else if (ss)
            ss->append(1, *c);
    }
    if (!ss)
    {
        return str;
    }
    else
    {
        std::string ret = *ss;
        delete ss;
        return ret;
    }
}

// url编码
std::string StringUtil::UrlDeconde(const std::string &str, bool convert_space_to_plus)
{
    std::string *ss = nullptr;
    const char *end = ss->c_str() + str.size();

    for (const char *c = str.c_str(); c < end; ++c)
    {
        if (*c == '+' && convert_space_to_plus)
        {
            if (!ss)
            {
                ss = new std::string;
                ss->append(str.c_str(), c - str.c_str());
            }
            ss->append(1, ' ');
        }
        else if (*c == '%' && (c + 2) < end && isdigit(*(c + 1) && isdigit(*(c + 2))))
        {
            if (!ss)
            {
                ss = new std::string;
                ss->append(str.c_str(), c - str.c_str());
            }
            ss->append(1, (char)(xdigit_chars[(int)*(c + 1)] << 4 | xdigit_chars[(int)*(c + 2)]));
            c += 2;
        }
        else if (ss)
        {
            ss->append(1, *c);
        }
    }
    if (!ss)
    {
        return str;
    }
    else
    {
        std::string ret = *ss;
        delete ss;
        return ret;
    }
}

// 移除字符串首尾的指定字符串
std::string StringUtil::Trim(const std::string &str, const std::string &delimit)
{
    auto begin = str.find_first_not_of(delimit);
    if (begin == std::string::npos)
    {
        return "";
    }
    auto end = str.find_last_not_of(delimit);
    return str.substr(begin, end - begin + 1);
}
// 移除字符串首部的指定字符串
std::string StringUtil::Trimleft(const std::string &str, const std::string &delimit)
{
    auto begin = str.find_first_not_of(delimit);
    if (begin == std::string::npos)
    {
        return "";
    }
    return str.substr(begin);
}
// 移除字符串尾部的指定字符串
std::string StringUtil::TrimRight(const std::string &str, const std::string &delimit)
{
    auto end = str.find_last_not_of(delimit);
    if (end == std::string::npos)
    {
        return "";
    }
    return str.substr(0, end);
}

// 宽字符串转字符串
// char* setlocale(int category, const char* locale);
// category：指定要设置的本地化类别。常见的类别有：
// LC_ALL：设置所有类别的本地化信息。
// LC_COLLATE：设置排序和比较字符串时的本地化规则。
// LC_CTYPE：设置字符分类和转换规则（如大小写转换）。
// LC_MONETARY：设置货币格式。
// LC_NUMERIC：设置数字格式（如小数点和千位分隔符）。
// LC_TIME：设置日期和时间格式。
// locale：指定要设置的本地化信息。这可以是一个字符串，表示特定的地区（如 "en_US"、"zh_CN" 等），或者是一个空指针，表示使用系统默认的本地化信息。
std::string StringUtil::WStringToString(const std::wstring &ws)
{
    // 保存 当前本地化设置
    std::string str_local = setlocale(LC_ALL, "");

    // 获取宽字符的 c风格表示
    const wchar_t *wch_src = ws.c_str();

    // 计算转换后的字符串大小分配内存
    size_t n_dest_size = wcstombs(nullptr, wch_src, 0) + 1;
    char *ch_dest = new char[n_dest_size];
    memset(ch_dest, 0, n_dest_size);

    // 构造结果字符串并释放内存
    wcstombs(ch_dest, wch_src, n_dest_size);
    std::string str_result = ch_dest;
    delete[] ch_dest;

    // 恢复原始本地初始化配置
    setlocale(LC_ALL, str_local.c_str());

    return str_result;
}
std::wstring StringUtil::StringToWstring(const std::string &str)
{
    // 保存当前本地化设置
    std::string str_local = setlocale(LC_ALL, "");

    // 获取普通字符串的 C 风格表示
    const char *chSrc = str.c_str();

    // 计算转换后的宽字符串大小并分配内存
    size_t n_dest_size = mbstowcs(nullptr, chSrc, 0) + 1;
    wchar_t *wch_dest = new wchar_t[n_dest_size];
    wmemset(wch_dest, 0, n_dest_size);

    // 将普通字符串转换为宽字符串
    mbstowcs(wch_dest, chSrc, n_dest_size);

    // 构造结果宽字符串并释放内存
    std::wstring wstr_result = wch_dest;
    delete[] wch_dest;

    // 恢复原始本地化设置
    setlocale(LC_ALL, str_local.c_str());

    return wstr_result;
}